package com.learning.level3;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author adolphw
 *
 * LockSupport 线程工具类 阻塞和唤醒线程
 *
 * unpark可以在阻塞之前执行
 * 先unpark a仍能被b通知唤醒
 *
 * 线程阻塞会出 unpark最多出一个凭证一个凭证permit，
 *
 * 为什么可以先唤醒线程后阻塞线程
 * 因为unpark获得了一个凭证，之后再调用park方法，就可以名正言顺的凭证消费，故不会阻塞
 *
 * 为什么唤醒两次后阻塞两次，但最终结果还是会阻塞线程
 * 因为凭证的数量最多为1，连续调用两次unpark和调用一次unpark效果一样，只会增加一个凭证，而调用两次park则需要消费两个凭证，凭证不够
 * 不能放行
 *
 */
public class LockSupportDemo {
    static Object objectLock = new Object();
    static Lock lock = new ReentrantLock();
    static Condition condition = lock.newCondition();


    public static void main(String[] args) {

      Thread a=  new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t-------come in");
            LockSupport.park();//被阻塞 等待3秒后被b线程唤醒
            System.out.println(Thread.currentThread().getName() + "\t---------被唤醒");
        }, "A");
        a.start();

        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Thread b = new Thread(() -> {
            LockSupport.unpark(a);
            System.out.println(Thread.currentThread().getName()+"\t ------通知");
        }, "b");
        b.start();

    }

    private static void awaitNotify() {
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t" + "--------come in");
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();

                System.out.println("被唤醒");
            }finally {
                lock.unlock();
            }


        }, "C").start();

        new Thread(() -> {
            lock.lock();

            try {
                System.out.println(Thread.currentThread().getName() + "\t" + "--------tongzhi");
                condition.signal();
            } catch (Exception e) {

            }finally {
                lock.unlock();
            }

        }, "D").start();
    }

    private static void waitNotify() {
        new Thread(() -> {
            synchronized (objectLock) {
                System.out.println(Thread.currentThread().getName() + "\t" + "--------come in");
                try {
                    objectLock.wait();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t " + "--------被唤醒");

            }
        }, "A").start();

        new Thread(() -> {
            synchronized (objectLock) {

                    objectLock.notify();

                System.out.println(Thread.currentThread().getName() + "\t " + "--------通知");

            }
        }, "B").start();
    }
}
